package com.hissy.cn.redis;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

/**
 * Created by zhangyanfei on 2019/1/28.
 *
 * 获取多配置jedisPool
 * 根据namespace获取指定配置的连接池
 *
 * 如：配置为 redis.default.port，则namespace为default，获取default相关配置的jedispool对应的实例
 *
 * 使用方式：
 * 通过内部类单例获取，使用的时候初始化jedispool
 * 由jvm类加载机制保证线程安全
 *
 * jedis 创建工厂
 *
 * -> JedisConfigFactory
 * -> JedisPoolFactory  多数据源
 * @author zhangyanfei
 * @date 2019/01/28
 */
public class JedisClientFactory {
    private static final Logger logger= LoggerFactory.getLogger(JedisClientFactory.class);

    //已经加载过的连池map
    private static Map<String,JedisPool> INITIAL_JEDISPOOL=new HashMap<>();

    //默认的连接池
    private static JedisPool DEFAULT_JEDISPOOL=null;

    // 是否初始化完成
    private static boolean INIT_IS_DONE=false;

    private JedisClientFactory(){}


    /**
     * 初始化jedisclient工厂
     * @author sxx
     * @date 2018-09-21 11:43
     * @note sxx@2018-09-21 11:43创建
     */
    private void initJedisClientFactory () {
        // 初始化配置
        Map<String, JedisPoolBean> jedisPoolBeanList = JedisConfigFactory.getJedisConfigList();
        for (Map.Entry<String, JedisPoolBean> entry : jedisPoolBeanList.entrySet()) {
            String nameSpace = entry.getKey();
            // 初始化线程池
            JedisPool jedisPool = null;
            try {
                // 创建jedis连接池
                jedisPool = entry.getValue().initJedisPool();
            } catch (Exception e) {
                logger.error("init jedisPool error, the namespace is : " + nameSpace, e);
            }

            if (jedisPool == null) {
                continue;
            }
            INITIAL_JEDISPOOL.put(nameSpace, jedisPool);
            // 设置默认jedispool
            if (JedisPoolBeanConstant.DEFAULT_REDIS_NAMESPACE.equals(nameSpace)) {
                DEFAULT_JEDISPOOL = jedisPool;
            }
        }

        if (!CollectionUtils.isEmpty(INITIAL_JEDISPOOL)) {
            INIT_IS_DONE = true;
        } else {
            logger.error("initJedisClientFactory error");
            throw new IllegalArgumentException("多套redis配置,初始化jedispool全部失败");
        }
    }

    /**
     * 获取默认jedis Client
     *
     * 请注意，需要配置正确的默认namespace
     * @see JedisPoolBeanConstant#DEFAULT_REDIS_NAMESPACE
     *
     * @return redis.clients.jedis.Jedis
     * @author sxx
     * @date 2018-08-10 17:15
     * @note sxx@2018-08-10 17:15创建
     */
    public Jedis getDefaultJedisClient() {
        // valid initcondition
        if (!INIT_IS_DONE) {
            synchronized (this) {
                if (!INIT_IS_DONE) {
                    this.initJedisClientFactory();
                }
            }
        }

        if (null == DEFAULT_JEDISPOOL) {
            return null;
        }
        return DEFAULT_JEDISPOOL.getResource();
    }

    /**
     * 根据传入的namespace获取指定的配置
     * 如：配置为 redis.first.port，则namespace为first，获取第一套配置的jedis实例
     *
     * @return redis.clients.jedis.Jedis
     * @brief 返回jedis客户端
     * @author sxx
     * @date 2018-07-17 17:26
     * @note sxx@2018-07-17 17:26创建
     */
    public Jedis getJedisClientByNameSpace(String namespace) {
        //valid namespace
        if (StringUtils.isBlank(namespace)) {
            throw new NullPointerException("namespace should not be blank!");
        }

        // valid initcondition
        if (!INIT_IS_DONE) {
            synchronized (this) {
                if (!INIT_IS_DONE) {
                    this.initJedisClientFactory();
                }
            }
        }

        JedisPool jedisPool = INITIAL_JEDISPOOL.get(namespace);
        if (null == jedisPool) {
            return null;
        }
        return jedisPool.getResource();
    }

    public static JedisClientFactory getInstance(){
        return InnerInstance.INSTANCE;
    }

    /**
     * 静态内部类 成员变量是个全局唯一
     * JVM  常量池
     */
    private final static class InnerInstance {
        private final static JedisClientFactory INSTANCE = new JedisClientFactory();
    }
}
